package com.caltco.cargo.ops.auth.component;


import cn.hutool.core.util.ObjectUtil;
import com.caltco.cargo.ops.auth.bo.AdminUserDetails;
import com.caltco.cargo.ops.auth.entity.UserEntity;
import com.caltco.cargo.ops.auth.service.UserService;
import com.caltco.cargo.ops.auth.utils.JwtTokenUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Map;

/**
 * @program: agilefast-framework
 * @description: JWT登录授权过滤器
 * @author: yehao
 * @create: 2022-07-20 13:41
 **/
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${agilefast.redis.open}")
    private String isOpenRedis;
    @Autowired
    private UserService sysUserService;
    public static final String USER_KEY = "userId";
    public static final String USER_NAME = "userName";
    public static final String REAL_NAME = "realName";
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        String authHeader = request.getHeader(tokenHeader);
        AdminUserDetails userDetails = null;
        String username = null;
        if (authHeader != null && authHeader.startsWith(tokenHead)) {
            // The part after "Bearer "
            // 获取JWT-Token
            String authToken = authHeader.substring(tokenHead.length());
            // JWT解析用户信息
            Map<String,Object> user = jwtTokenUtil.getUserNameFromToken(authToken);
            // 判断用户名是否为空
            if (ObjectUtil.isNotNull(user.get("username"))){
                username = user.get("username").toString();
            }

            // 根据用户名查询redis中的用户信息
            LOGGER.info("checking username:{}",username);
            if (isOpenRedis.equals("true")) {
                userDetails = username != null ? sysUserService.loadUserByUsernameRedis(username) : null;
            } else {
                UserEntity userEntity = new UserEntity();
                Long userId = Long.parseLong(user.get("userId").toString());
                userEntity.setUserId(userId);
                userEntity.setUsername(username);
                userDetails = new AdminUserDetails(userEntity, authToken);
            }

            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                if(userDetails != null && userDetails.getToken()!= null && authToken.equals(userDetails.getToken())){
                    if (jwtTokenUtil.validateToken(authToken,userDetails)) {
                        UsernamePasswordAuthenticationToken authenticationToken =
                                new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                        Long userId = Long.parseLong(user.get("userId").toString());

                        request.setAttribute(USER_KEY, userId);
                        request.setAttribute(USER_NAME, username);
                        request.setAttribute(REAL_NAME, userDetails.getUserEntity().getChineseName());
                    }
                }

            }
        }
        chain.doFilter(request, response);
    }
}
